home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / mtools.lha / mtools-2.0.7 / mwrite.c < prev    next >
C/C++ Source or Header  |  1992-09-10  |  8KB  |  368 lines

  1. /*
  2.  * Write (copy) a Unix file to MSDOS
  3.  *
  4.  * Emmet P. Gray            US Army, HQ III Corps & Fort Hood
  5.  * ...!uunet!uiucuxc!fthood!egray    Attn: AFZF-DE-ENV
  6.  * fthood!egray@uxc.cso.uiuc.edu    Directorate of Engineering & Housing
  7.  *                     Environmental Management Office
  8.  *                     Fort Hood, TX 76544-5057
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <signal.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include "msdos.h"
  16. #include "patchlevel.h"
  17.  
  18. int fd = -1;                /* the file descriptor for the device */
  19. int dir_start;                /* starting sector for directory */
  20. int dir_len;                /* length of directory (in sectors) */
  21. int dir_entries;            /* number of directory entries */
  22. int clus_size;                /* cluster size (in sectors) */
  23. char *mcwd;                /* the Current Working Directory */
  24. int fat_error;                /* FAT error detected? */
  25.  
  26. int full = 0;
  27. int textmode = 0;
  28. int nowarn = 0;
  29. static int got_signal();
  30. static struct directory *writeit();
  31. static long free_space();
  32.  
  33. main(argc, argv)
  34. int argc;
  35. char *argv[];
  36. {
  37.     extern int optind;
  38.     extern char *optarg;
  39.     int i, entry, ismatch, nogo, slot, single, got_one, missed_one;
  40.     int c, oops, verbose, first, mod_time;
  41.     unsigned int dot, start;
  42.     char *filename, *newfile, *get_name(), get_drive();
  43.     char *unix_name(), ans[10], *pathname, *get_path(), *fix_mcwd();
  44.     char tmp[MAX_PATH], target[13], *strcat(), *strcpy(), drive;
  45.     unsigned char *fixed, *dos_name();
  46.     void exit(), fat_write(), dir_write(), disk_flush(), dir_flush();
  47.     struct directory *dir, *dir_read();
  48.                     /* catch signals */
  49.     signal(SIGINT, (SIG_TYPE(*) ()) got_signal);
  50.     signal(SIGTERM, (SIG_TYPE(*) ()) got_signal);
  51.     signal(SIGQUIT, (SIG_TYPE(*) ()) got_signal);
  52.                     /* get command line options */
  53.     oops = 0;
  54.     verbose = 0;
  55.     mod_time = 0;
  56.     got_one = 0;
  57.     missed_one = 0;
  58.     while ((c = getopt(argc, argv, "tnvm")) != EOF) {
  59.         switch (c) {
  60.             case 't':
  61.                 textmode = 1;
  62.                 break;
  63.             case 'n':
  64.                 nowarn = 1;
  65.                 break;
  66.             case 'v':
  67.                 verbose = 1;
  68.                 break;
  69.             case 'm':
  70.                 mod_time = 1;
  71.                 break;
  72.             default:
  73.                 oops = 1;
  74.                 break;
  75.         }
  76.     }
  77.  
  78.     if (oops || (argc - optind) < 2) {
  79.         fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE);
  80.         fprintf(stderr, "Usage: %s [-tnvm] unixfile msdosfile\n", argv[0]);
  81.         fprintf(stderr, "       %s [-tnvm] unixfile [unixfiles...] msdosdirectory\n", argv[0]);
  82.         exit(1);
  83.     }
  84.     mcwd = fix_mcwd();
  85.  
  86.     drive = get_drive(argv[argc - 1]);
  87.     if (init(drive, 2)) {
  88.         fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive);
  89.         exit(1);
  90.     }
  91.  
  92.     filename = get_name(argv[argc - 1]);
  93.     pathname = get_path(argv[argc - 1]);
  94.  
  95.     /*
  96.      * Move to "first guess" directory so we can see if filename is also
  97.      * a directory.
  98.      */
  99.     if (subdir(drive, pathname))
  100.         exit(1);
  101.                     /* test if last argv is a dir */
  102.     if (is_dir(filename) || *filename == '\0') {
  103.         if (*filename) {
  104.             strcpy(tmp, pathname);
  105.             if (tmp[strlen(tmp) -1] != '/')
  106.                 strcat(tmp, "/");
  107.             strcat(tmp, filename);
  108.  
  109.             if (subdir(drive, tmp))
  110.                 exit(1);
  111.         }
  112.         single = 0;
  113.     }
  114.     else {
  115.         single = 1;
  116.                     /* too many arguments */
  117.         if ((argc - optind) != 2) {
  118.             fprintf(stderr, "%s: Too many arguments or destination directory omitted\n", argv[0]);
  119.             exit(1);
  120.         }
  121.     }
  122.  
  123.     for (i = optind; i < argc - 1; i++) {
  124.         if (single)
  125.             fixed = dos_name(argv[argc - 1], verbose);
  126.         else
  127.             fixed = dos_name(argv[i], verbose);
  128.  
  129.         strcpy(target, unix_name(fixed, fixed + 8));
  130.                     /* see if exists and get slot */
  131.         ismatch = 0;
  132.         slot = -1;
  133.         dot = 0;
  134.         nogo = 0;
  135.         first = 1;
  136.         for (entry = 0; entry < dir_entries; entry++) {
  137.             dir = dir_read(entry);
  138.                     /* save the '.' entry info */
  139.             if (first) {
  140.                 first = 0;
  141.                 if ((dir->attr & 0x10) && dir->name[0] == '.') {
  142.                     dot = dir->start[1] * 0x100 + dir->start[0];
  143.                     continue;
  144.                 }
  145.             }
  146.                     /* is empty */
  147.             if (dir->name[0] == 0x0) {
  148.                 if (slot < 0)
  149.                     slot = entry;
  150.                 break;
  151.             }
  152.                     /* is erased */
  153.             if (dir->name[0] == 0xe5) {
  154.                 if (slot < 0)
  155.                     slot = entry;
  156.                 continue;
  157.             }
  158.                     /* is dir or volume label */
  159.             if ((dir->attr & 0x10) || (dir->attr & 0x08))
  160.                 continue;
  161.  
  162.             newfile = unix_name(dir->name, dir->ext);
  163.  
  164.                     /* if file exists, delete it first */
  165.             if (!strcmp(target, newfile)) {
  166.                 ismatch = 1;
  167.                 start = dir->start[1] * 0x100 + dir->start[0];
  168.                 if (nowarn) {
  169.                     if (fat_free(start))
  170.                         break;
  171.                     dir->name[0] = 0xe5;
  172.                     dir_write(entry, dir);
  173.                     if (slot < 0)
  174.                         slot = entry;
  175.                 }
  176.                 else {
  177.                     /* CONSTCOND */
  178.                     while (1) {
  179.                         printf("File \"%s\" exists, overwrite (y/n) ? ", target);
  180.                         gets(ans);
  181.                         if (ans[0] == 'n' || ans[0] == 'N') {
  182.                             nogo = 1;
  183.                             break;
  184.                         }
  185.                         if (ans[0] == 'y' || ans[0] == 'Y') {
  186.                             if (fat_free(start))
  187.                                 break;
  188.                             dir->name[0] = 0xe5;
  189.                             dir_write(entry, dir);
  190.                             if (slot < 0)
  191.                                 slot = entry;
  192.                             break;
  193.                         }
  194.                     }
  195.                 }
  196.             }
  197.             if (ismatch)
  198.                 break;
  199.         }
  200.         if (fat_error) {
  201.             missed_one++;
  202.             break;
  203.         }
  204.  
  205.         if (nogo)        /* chickened out... */
  206.             continue;
  207.                     /* no '.' entry means root directory */
  208.         if (dot == 0 && slot < 0) {
  209.             fprintf(stderr, "%s: No directory slots\n", argv[0]);
  210.             missed_one++;
  211.             break;
  212.         }
  213.                     /* make the directory grow */
  214.         if (dot && slot < 0) {
  215.             if (dir_grow(dot)) {
  216.                 fprintf(stderr, "%s: Disk full\n", argv[0]);
  217.                 missed_one++;
  218.                 break;
  219.             }
  220.                     /* first entry in 'new' directory */
  221.             slot = entry;
  222.         }
  223.                     /* write the file */
  224.         if (dir = writeit(fixed, argv[i], verbose, mod_time, single, target)) {
  225.             dir_write(slot, dir);
  226.             got_one++;
  227.         }
  228.         else
  229.             missed_one++;
  230.  
  231.         if (full) {
  232.             fprintf(stderr, "%s: Disk full\n", argv[0]);
  233.             break;
  234.         }
  235.         if (single)
  236.             break;
  237.     }
  238.                     /* write the FAT, flush the buffers */
  239.     fat_write();
  240.     dir_flush();
  241.     disk_flush();
  242.     close(fd);
  243.     if (got_one && missed_one)
  244.         exit(2);
  245.     if (missed_one)
  246.         exit(1);
  247.     exit(0);
  248. }
  249.  
  250. /*
  251.  * Open the named file for read, create the cluster chain, return the
  252.  * directory structure or NULL on error.
  253.  */
  254.  
  255. static struct directory *
  256. writeit(fixed, path, verbose, mod_time, single, target)
  257. unsigned char *fixed;
  258. char *path;
  259. int verbose, mod_time, single;
  260. char *target;
  261. {
  262.     FILE *fp;
  263.     unsigned int fat, next_fat();
  264.     long filesize, file_write(), size, time(), now;
  265.     struct directory *dir, *mk_entry();
  266.     struct stat stbuf;
  267.  
  268.     if (stat(path, &stbuf) < 0) {
  269.         fprintf(stderr, "Can't stat \"%s\"\n", path);
  270.         return(NULL);
  271.     }
  272.  
  273.     if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
  274.         if (verbose)
  275.             fprintf(stderr, "\"%s\" is a directory\n", path);
  276.         return(NULL);
  277.     }
  278.  
  279.     if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
  280.         if (verbose)
  281.             fprintf(stderr, "\"%s\" is not a regular file\n", path);
  282.         return(NULL);
  283.     }
  284.  
  285.     if (!(fp = fopen(path, "r"))) {
  286.         fprintf(stderr, "Can't open \"%s\" for read\n", path);
  287.         return(NULL);
  288.     }
  289.  
  290.     if (!single)
  291.         printf("Copying %s\n", target);
  292.  
  293.                     /* will it fit? */
  294.     filesize = stbuf.st_size;
  295.     if (filesize > free_space()) {
  296.         full = 1;
  297.         return(NULL);
  298.     }
  299.                     /* preserve mod time? */
  300.     if (mod_time)
  301.         now = stbuf.st_mtime;
  302.     else
  303.         time(&now);
  304.  
  305.                     /* if a zero length file */
  306.     if (filesize == 0L) {
  307.         dir = mk_entry(fixed, 0x20, 0, 0L, now);
  308.         return(dir);
  309.     }
  310.  
  311.     if ((fat = next_fat(0)) == 1) {
  312.         full = 1;
  313.         fclose(fp);
  314.         return(NULL);
  315.     }
  316.     if ((size = file_write(fp, fat, filesize, textmode)) < 0) {
  317.         fclose(fp);
  318.         return(NULL);
  319.     }
  320.     fclose(fp);
  321.  
  322.     dir = mk_entry(fixed, 0x20, fat, size, now);
  323.     return(dir);
  324. }
  325.  
  326. /*
  327.  * Do a graceful exit if the program is interrupted.  This will reduce
  328.  * (but not eliminate) the risk of generating a corrupted disk on
  329.  * a user abort.
  330.  */
  331.  
  332. static int
  333. got_signal()
  334. {
  335.     void exit(), disk_flush(), fat_write(), dir_flush();
  336.  
  337.     if (fd < 0)
  338.         exit(1);
  339.     fat_write();
  340.     dir_flush();
  341.     disk_flush();
  342.     close(fd);
  343.     exit(1);
  344. }
  345.  
  346.  
  347. /*
  348.  * Get the amount of remaining free space
  349.  */
  350.  
  351. static long
  352. free_space()
  353. {
  354.     register unsigned int i;
  355.     long total;
  356.     extern unsigned int num_clus;
  357.     unsigned int fat_decode();
  358.  
  359.     total = 0L;
  360.     for (i = 2; i < num_clus + 2; i++) {
  361.                     /* if fat_decode returns zero */
  362.         if (!fat_decode(i))
  363.             total += clus_size;
  364.     }
  365.     total *= MSECTOR_SIZE;
  366.     return(total);
  367. }
  368.